package com.ehome.poct.base.dao.device.repository;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ehome.core.util.BeanConvertUtil;
import com.ehome.mybatisplus.support.AbstractCrudRepository;
import com.ehome.poct.base.api.constant.PackageType;
import com.ehome.poct.base.api.dto.device.SoftwareUpgradeInfo;
import com.ehome.poct.base.api.dto.device.SoftwareUpgradeQry;
import com.ehome.poct.base.api.dto.device.TestDeviceVersionDTO;
import com.ehome.poct.base.api.dto.device.VersionStatusQry;
import com.ehome.poct.base.dao.device.entity.TestDeviceVersionDO;
import com.ehome.poct.base.dao.device.mapper.TestDeviceVersionMapper;
import com.ehome.poct.base.device.repository.TestDeviceVersionRepository;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import java.util.List;

/**
 * 版本表RepositoryImpl
 *
 * @author yjm
 * @Date 2021-12-06 16:53
 */
@Repository
@Slf4j
public class TestDeviceVersionRepositoryImpl extends AbstractCrudRepository<TestDeviceVersionDO, TestDeviceVersionDTO> implements TestDeviceVersionRepository {

    @Autowired
    private TestDeviceVersionMapper mapper;

    @Override
    public Boolean getVersionCode(Integer packageType, String deviceType, Integer versionCode) {
        TestDeviceVersionDO versionDO = mapper.selectOne(Wrappers.<TestDeviceVersionDO>lambdaQuery()
                .eq(TestDeviceVersionDO::getPackageType, packageType)
                .like(TestDeviceVersionDO::getDeviceType, deviceType)
                .eq(TestDeviceVersionDO::getVersionCode,versionCode)
                .orderByDesc(TestDeviceVersionDO::getCreateTime)
                .last("limit 1"));

        if (ObjectUtil.isEmpty(versionDO)) {
            return false;
        }
        return true;
    }

    @Override
    public Boolean getSoftVersionCode(Integer packageType, String deviceType, String packageId, Integer versionCode) {
        TestDeviceVersionDO versionDO = mapper.selectOne(Wrappers.<TestDeviceVersionDO>lambdaQuery()
                .eq(TestDeviceVersionDO::getPackageType, packageType)
                .like(TestDeviceVersionDO::getDeviceType, deviceType)
                .eq(TestDeviceVersionDO::getVersionCode,versionCode)
                .eq(TestDeviceVersionDO::getPackageId,packageId)
                .orderByDesc(TestDeviceVersionDO::getCreateTime)
                .last("limit 1"));

        if (ObjectUtil.isEmpty(versionDO)) {
            return false;
        }
        return true;
    }

    @Override
    public String getVersion(Integer packageType, Integer deviceType) {
        List<TestDeviceVersionDO> hardwareVersionDOs = mapper.selectList(Wrappers.<TestDeviceVersionDO>lambdaQuery()
                .eq(TestDeviceVersionDO::getPackageType, packageType)
                .eq(TestDeviceVersionDO::getDeviceType, deviceType)
                .orderByDesc(TestDeviceVersionDO::getCreateTime)
                .last("limit 1"));
        if (ObjectUtil.isEmpty(hardwareVersionDOs)) {
            return "";
        }
        return hardwareVersionDOs.get(0).getVersion();
    }

    @Override
    public String minVersion(Integer packageType, Integer deviceType,String packageId) {
        List<TestDeviceVersionDO> hardwareVersionDOs = mapper.selectList(Wrappers.<TestDeviceVersionDO>lambdaQuery()
                .eq(TestDeviceVersionDO::getPackageType, packageType)
                .eq(TestDeviceVersionDO::getDeviceType, deviceType)
                .eq(ObjectUtil.isNotEmpty(packageId),TestDeviceVersionDO::getPackageId,packageId)
                .orderByAsc(TestDeviceVersionDO::getCreateTime)
                .last("limit 1"));
        if (ObjectUtil.isEmpty(hardwareVersionDOs)) {
            return "";
        }
        return hardwareVersionDOs.get(0).getVersion();
    }

    @Override
    public String maxVersion(Integer packageType, Integer deviceType,String packageId) {
        List<TestDeviceVersionDO> hardwareVersionDOs = mapper.selectList(Wrappers.<TestDeviceVersionDO>lambdaQuery()
                .eq(TestDeviceVersionDO::getPackageType, packageType)
                .eq(TestDeviceVersionDO::getDeviceType, deviceType)
                .eq(ObjectUtil.isNotEmpty(packageId),TestDeviceVersionDO::getPackageId,packageId)
                .orderByDesc(TestDeviceVersionDO::getCreateTime)
                .last("limit 1"));
        if (ObjectUtil.isEmpty(hardwareVersionDOs)) {
            return "";
        }
        return hardwareVersionDOs.get(0).getVersion();
    }

    @Override
    public List<TestDeviceVersionDTO> newVersion(TestDeviceVersionDTO dto) {
        var wrapper = getTestDeviceVersionQueryWrapper(dto);
        if (dto.getPackageType().equals(PackageType.FIRMWARE.ordinal())) {
            wrapper.select("max(version_code) as versionCode,project_name as projectName,package_type as packageType").groupBy("project_name", "package_type");
        } else {
            wrapper.select("max(version_code) as versionCode,package_id as packageId,package_type as packageType").groupBy( "package_type", "package_id");
        }
        var list = mapper.selectList(wrapper);
        var result = Lists.newArrayList();
        for (TestDeviceVersionDO d : list) {
            TestDeviceVersionDO tdv = this.selectOne(d);
            if(StrUtil.isNotEmpty(dto.getMinFirmwareVersion())){
                if (StrUtil.isNotEmpty(tdv.getMinFirmwareVersion()) && compareVersion(dto.getMinFirmwareVersion(),tdv.getMinFirmwareVersion()) < 0) {
                    continue;
                }
            }
            if(StrUtil.isNotEmpty(dto.getMinSoftwareVersion())){
                if (StrUtil.isNotEmpty(tdv.getMinSoftwareVersion()) && compareVersion(dto.getMinSoftwareVersion(),tdv.getMinSoftwareVersion()) < 0)  {
                    continue;
                }
            }
            result.add(tdv);
        }
        return BeanConvertUtil.convertBeanList(result, TestDeviceVersionDTO.class);
    }

    private QueryWrapper<TestDeviceVersionDO> getTestDeviceVersionQueryWrapper(TestDeviceVersionDTO dto) {
        var wrapper = Wrappers.<TestDeviceVersionDO>query();
        wrapper.eq(ObjectUtil.isNotEmpty(dto.getVersionStatus()),"version_status", dto.getVersionStatus())
                .eq(ObjectUtil.isNotEmpty(dto.getPackageType()),"package_type", dto.getPackageType())
                .eq(StrUtil.isNotEmpty(dto.getPackageId()), "package_id", dto.getPackageId())
                .eq(StrUtil.isNotEmpty(dto.getDeviceVersionType()), "device_version_type", dto.getDeviceVersionType());
        if(StrUtil.isNotEmpty(dto.getProjectName()) && PackageType.FIRMWARE.ordinal() == dto.getPackageType()){
            wrapper.like(StrUtil.isNotEmpty(dto.getProjectName()), "project_name", dto.getProjectName());
        }
        return wrapper;
    }

    @Override
    public Integer getCode(String version) {
        List<TestDeviceVersionDO> testDeviceVersionDO = mapper.selectList(Wrappers.<TestDeviceVersionDO>lambdaQuery()
                .eq(TestDeviceVersionDO::getVersion, version)
                .last("limit 1"));
        if (ObjectUtil.isEmpty(testDeviceVersionDO)) {
            return 0;
        }
        return testDeviceVersionDO.get(0).getVersionCode();
    }

    @Override
    public void updateStatus(VersionStatusQry qry) {
        TestDeviceVersionDO testDeviceVersionDO = mapper.selectById(qry.getDeviceVersionId());
        testDeviceVersionDO.setVersionStatus(qry.getVersionStatus());
        mapper.updateById(testDeviceVersionDO);
    }

    @Override
    public List<TestDeviceVersionDTO> getSoftwareUpgradeInfo(SoftwareUpgradeQry qry) {
        QueryWrapper<TestDeviceVersionDO> wrapper = Wrappers.query();
        wrapper.eq(ObjectUtil.isNotEmpty(qry.getPackageType()), "package_type", qry.getPackageType())
                .like(StrUtil.isNotEmpty(qry.getProjectName()), "project_name", qry.getProjectName());

        List<SoftwareUpgradeInfo> list = qry.getList();
        wrapper.and(d -> {
            for (SoftwareUpgradeInfo f : list) {
                d.or(c -> {
                    c.eq("version", f.getVersion())
                            .eq("version_code", f.getVersionCode())
                            .eq("package_name", f.getPackageName())
                            .eq("package_id", f.getPackageId());
                });
            }
        });
        List<TestDeviceVersionDO> dos = mapper.selectList(wrapper);
        return BeanConvertUtil.convertBeanList(dos, TestDeviceVersionDTO.class);
    }

    @Override
    public boolean selectVersion(String name,String deviceType,Integer packageType) {
        TestDeviceVersionDO testDeviceVersionDO = mapper.selectOne(Wrappers.<TestDeviceVersionDO>lambdaQuery()
                .eq(TestDeviceVersionDO::getVersion,name)
                .like(TestDeviceVersionDO::getDeviceType,deviceType)
                .eq(TestDeviceVersionDO::getPackageType,packageType)
                .last("limit 1"));
        if (ObjectUtil.isEmpty(testDeviceVersionDO)){
            return false;
        }
        return true;
    }

    @Override
    public boolean selVersion(String name, String packageId,String deviceType,Integer packageType) {
        TestDeviceVersionDO testDeviceVersionDO = mapper.selectOne(Wrappers.<TestDeviceVersionDO>lambdaQuery()
                .eq(TestDeviceVersionDO::getVersion,name)
                .eq(TestDeviceVersionDO::getPackageId,packageId)
                .like(TestDeviceVersionDO::getDeviceType,deviceType)
                .eq(TestDeviceVersionDO::getPackageType,packageType)
                .last("limit 1"));
        if (ObjectUtil.isEmpty(testDeviceVersionDO)){
            return false;
        }
        return true;
    }

    public static Integer compareVersion(String version1, String version2) {
        try {
            if (version1 == null || version2 == null) {
                throw new IllegalArgumentException("Bad version number");
            }
            String[] versionArray1 = version1.split("\\.");
            String[] versionArray2 = version2.split("\\.");
            if (versionArray1.length != 3 || versionArray2.length != 3) {
                throw new IllegalArgumentException("Bad version number");
            }
            // 逐段比较版本号，先比较第一位
            Integer result = null;
            for (int i = 0; i < 3; i++) {
                Integer v1 = Integer.parseInt(versionArray1[i]);
                Integer v2 = Integer.parseInt(versionArray2[i]);
                result = Integer.compare(v1 - v2, 0);
                if (result != 0) {
                    break;
                }
            }
            return result;
        } catch (Exception ex) {
            log.error("Error to compare version", ex);
            return -2;
        }
    }
}
